//
// Created by LiuYou on 2021/8/28.
//

#include "HttpConnect2.hpp"
#include <sys/uio.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
#include <cerrno>
#include <cstdlib>
#include <cstdio>
#include <sys/mman.h>
#include <cstdarg>


static const char* ok_200_title = "OK";
static const char* error_400_title = "Bad Request";
static const char* error_400_form = "Your request has bad syntax or is inherently impossible to satisfy.\n";
static const char* error_403_title = "Forbidden";
static const char* error_403_form = "You do not have permission to get file from this server.\n";
static const char* error_404_title = "Not Found";
static const char* error_404_form = "The requested file was not found on this server.\n";
static const char* error_500_title = "Internal Error";
static const char* error_500_form = "There was an unusual problem serving the requested file.\n";
static const char* doc_root = "/var/www/html";//服务端资源页的路径，将其和HTTP请求中解析的m_url拼接形成资源页的位置



int HttpConnect::userCount = 0;//连接数
int HttpConnect::epollFd = -1;//事件表，注意是static故所有http_con类对象共享一个事件表




int setFdNonblocking(int fd)//将fd设置为非阻塞
{
    int old_option = fcntl( fd, F_GETFL );
    int new_option = old_option | O_NONBLOCK;
    fcntl( fd, F_SETFL, new_option );
    return old_option;
}

void addFdToEpoll(int epollfd, int fd, bool one_shot)//将fd添加到事件表epollfd
{
    epoll_event event;
    event.data.fd = fd;
    event.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
    if (one_shot) {
        event.events |= EPOLLONESHOT;
    }
    epoll_ctl( epollfd, EPOLL_CTL_ADD, fd, &event );
    setFdNonblocking( fd );
}

void removeFd(int epollfd, int fd)//将fd从事件表epollfd中移除
{
    epoll_ctl( epollfd, EPOLL_CTL_DEL, fd, 0 );
    close( fd );
}

void modFd(int epollfd, int fd, EPOLL_EVENTS ev)//EPOLLONESHOT需要重置事件后事件才能进行下次侦听
{
    epoll_event event;
    event.data.fd = fd;
    event.events = ev | EPOLLET | EPOLLONESHOT | EPOLLRDHUP;
    epoll_ctl( epollfd, EPOLL_CTL_MOD, fd, &event );
}


void HttpConnect::closeConnection(bool real_close)//关闭连接，从事件表中移除描述符
{
    if (real_close && (connectFd != -1)) {
        //modfd( m_epollfd, m_sockfd, EPOLLIN );
        removeFd( epollFd, connectFd );
        connectFd = -1;
        userCount--;
    }
}

void HttpConnect::init(int sockfd, const sockaddr_in& addr)//初始化连接
{
    connectFd = sockfd;//sockfd是http连接对应的描述符用于接收http请求和http回答
    remoteAddress = addr;//客户端地址
    int error = 0;
    socklen_t len = sizeof( error );
    getsockopt( connectFd, SOL_SOCKET, SO_ERROR, &error, &len );
    int reuse = 1;
    setsockopt( connectFd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof( reuse ));//获取描述符状态，可以在调试时用
    addFdToEpoll( epollFd, sockfd, true );
    userCount++;//多了一个http用户

    init();//调用重载函数
}

void HttpConnect::init()//重载init函数进行些连接前的初始化操作
{
    checkState = CheckState::CHECK_STATE_REQUEST_LINE;
    linger = false;

    method = Method::GET;
    url = nullptr;
    version = nullptr;
    contentLength = 0;
    host = nullptr;
    startLine = 0;
    checkedIdx = 0;
    readIdx = 0;
    writeIdx = 0;
    memset( readBuf, '\0', READ_BUFFER_SIZE );
    memset( writeBuf, '\0', WRITE_BUFFER_SIZE );
    memset( realFile, '\0', FILE_NAME_LEN );
}

/*从状态机，用于解析出一行内容*/
LineStatus HttpConnect::parseLine() {
    char temp;
    //checked_index指向buffer（应用程序读缓冲区）中当前正在分析的字节，read_index指向buffer中客户数据尾部的下一个字节;
    //buffer中的第0 ~ checked_index字节都已分析完毕, 第checked_index ~ (read_index - 1)字节由下面的循环挨个分析
    for (; checkedIdx < readIdx; ++checkedIdx) {
        //获得当前要分析的字节；
        temp = readBuf[checkedIdx];
        //如果是“\r”，即回车符号，说明可能读取到一个完整的行
        if (temp == '\r') {
            //如果\r恰巧是目前buffer中最后一个已经被读入的客户数据，那么这次分析没有读取到完整的行，
            //返回LINE_OPEN表示还需要继续读取客户数据来进一步分析
            if ((checkedIdx + 1) == readIdx) {
                return LineStatus::LINE_OPEN;
            }
                //如果下一个字符是\n,说明读到一个完整的行
            else if (readBuf[checkedIdx + 1] == '\n') {
                readBuf[checkedIdx++] = '\0';
                readBuf[checkedIdx++] = '\0';
                return LineStatus::LINE_OK;
            }
            //否则，说明存在语法问题
            return LineStatus::LINE_BAD;
        }
            //如果当前字符是\n，说明也可能读到一个完整的行
            //not necessary
        else if (temp == '\n') {
            if ((checkedIdx > 1) && (readBuf[checkedIdx - 1] == '\r')) {
                readBuf[checkedIdx - 1] = '\0';
                readBuf[checkedIdx++] = '\0';
                return LineStatus::LINE_OK;
            }
            return LineStatus::LINE_BAD;
        }
    }
    //如果所有内容分析完毕都没有遇到\r字符，则返回LINE_OPEN，表示还需要继续读取客户数据才能进一步分析
    return LineStatus::LINE_OPEN;
}

// 循环读取客户数据，直到无数据可读或者对方关闭连接
bool HttpConnect::read() {
    if (readIdx >= READ_BUFFER_SIZE) {
        return false;
    }

    int bytes_read = 0;
    while (true) {
        // 从套接字接收数据，存储在m_read_buf缓冲区
        bytes_read = recv( connectFd, readBuf + readIdx, READ_BUFFER_SIZE - readIdx, 0 );
        if (bytes_read == -1) {
            // 非阻塞ET模式下，需要一次性将数据读完
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                break;
            }
            return false;
        } else if (bytes_read == 0) {
            return false;
        }

        // 修改m_read_idx的读取字节数
        readIdx += bytes_read;
    }
    return true;
}


HttpCode HttpConnect::parseRequestLine(char* text) {
    //strpbrk()函数检索两个字符串中首个相同字符的位置，其原型为：
    //    char *strpbrk( char *s1, char *s2)
    url = strpbrk( text, " \t" );

    //请求行中如果没有\t，则该HTTP请求有问题
    if (!url) {
        return HttpCode::BAD_REQUEST;
    }

    *url++ = '\0';

    char* method = text;
    //定义函数：int strcasecmp (const char *s1, const char *s2);
    //函数说明：strcasecmp()用来比较参数s1 和s2 字符串，比较时会自动忽略大小写的差异。
    //返回值：若参数s1 和s2 字符串相同则返回0。s1 长度大于s2 长度则返回大于0 的值，s1 长度若小于s2 长度则返回小于0 的值。
    if (strcasecmp( method, "GET" ) == 0) {
        this->method = Method::GET;
    } else {
        return HttpCode::BAD_REQUEST;
    }
    //strspn() 函数用来计算字符串 str 中连续有几个字符都属于字符串 accept，其原型为：
    //size_t strspn(const char *str, const char * accept);
    url += strspn( url, " \t" );
    version = strpbrk( url, " \t" );
    if (!version) {
        return HttpCode::BAD_REQUEST;
    }
    *version++ = '\0';
    version += strspn( version, " \t" );
    if (strcasecmp( version, "HTTP/1.1" ) != 0) {
        return HttpCode::BAD_REQUEST;
    }

    if (strncasecmp( url, "http://", 7 ) == 0) {
        url += 7;
        //strchr() 用来查找某字符在字符串中首次出现的位置，其原型为：
        //char * strchr (const char *str, int c)
        url = strchr( url, '/' );
    }

    if (!url || url[0] != '/') {
        return HttpCode::BAD_REQUEST;
    }
    //HTTP请求行处理完毕，状态转移到头部字段的分析
    checkState = CheckState::CHECK_STATE_HEADER;
    return HttpCode::NO_REQUEST;
}

/*解析http请求的一个头部信息*/
HttpCode HttpConnect::parseHeaders(char* text) {    //空行，头部字段解析完毕
    if (text[0] == '\0') {
        if (method == Method::HEAD) {
            return HttpCode::GET_REQUEST;
        }
        //如果HTTP请求有消息体，则还需要读取contentLength字节的消息体，从状态机转移到CHECK_STATE_CONTENT状态
        if (contentLength != 0) {
            checkState = CheckState::CHECK_STATE_CONTENT;
            return HttpCode::NO_REQUEST;
        }
        //否则，说明得到了一个完整的HTTP请求
        return HttpCode::GET_REQUEST;
    }
        //处理connection头部字段
    else if (strncasecmp( text, "Connection:", 11 ) == 0) {
        text += 11;
        text += strspn( text, " \t" );
        if (strcasecmp( text, "keep-alive" ) == 0) {
            linger = true;
        }
    }
        //处理Content_length头部字段
    else if (strncasecmp( text, "Content-Length:", 15 ) == 0) {
        text += 15;
        text += strspn( text, " \t" );
        contentLength = atol( text );
    }
        //处理host头部字段
    else if (strncasecmp( text, "Host:", 5 ) == 0) {
        text += 5;
        text += strspn( text, " \t" );
        host = text;
    } else {
        printf( "oop! unknow header %s\n", text );
    }

    return HttpCode::NO_REQUEST;

}

//消息体不解析，判断一下是否完整读入
HttpCode HttpConnect::parseContent(char* text) {
    if (readIdx >= (contentLength + checkedIdx)) {
        text[contentLength] = '\0';
        return HttpCode::GET_REQUEST;
    }

    return HttpCode::NO_REQUEST;
}

HttpCode HttpConnect::processRead() {
    LineStatus line_status = LineStatus::LINE_OK;
    HttpCode ret = HttpCode::NO_REQUEST;
    char* text = nullptr;

    while (((checkState == CheckState::CHECK_STATE_CONTENT) && (line_status == LineStatus::LINE_OK))
           || ((line_status = parseLine()) == LineStatus::LINE_OK)) {
        text = getLine();
        startLine = checkedIdx;
        printf( "got 1 http line: %s\n", text );

        switch (checkState) {
            case CheckState::CHECK_STATE_REQUEST_LINE: {
                ret = parseRequestLine( text );
                if (ret == HttpCode::BAD_REQUEST) {
                    return HttpCode::BAD_REQUEST;
                }
                break;
            }
            case CheckState::CHECK_STATE_HEADER: {
                ret = parseHeaders( text );
                if (ret == HttpCode::BAD_REQUEST) {
                    return HttpCode::BAD_REQUEST;
                } else if (ret == HttpCode::GET_REQUEST) {
                    return doRequest();
                }
                break;
            }
            case CheckState::CHECK_STATE_CONTENT: {
                ret = parseContent( text );
                if (ret == HttpCode::GET_REQUEST) {
                    return doRequest();
                }
                line_status = LineStatus::LINE_OPEN;
                break;
            }
            default: {
                return HttpCode::INTERNAL_ERROR;
            }
        }
    }

    return HttpCode::NO_REQUEST;
}

HttpCode HttpConnect::doRequest()//用于获取资源页文件的状态
{
    strcpy( realFile, doc_root );
    int len = strlen( doc_root );
    strncpy( realFile + len, url, FILE_NAME_LEN - len - 1 );
    if (stat( realFile, &fileStat ) < 0) {
        return HttpCode::NO_RESOURCE;//若资源页不存在则HTTP解析结果为404
    }

    if (!(fileStat.st_mode & S_IROTH)) {
        return HttpCode::FORBIDDEN_REQUEST;//资源没有权限获取
    }

    if (S_ISDIR( fileStat.st_mode )) {
        return HttpCode::BAD_REQUEST;//请求有错
    }

    int fd = open( realFile, O_RDONLY );
    fileAddress = (char*) mmap( nullptr, fileStat.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );//将资源页文件映射到内存
    close( fd );
    return HttpCode::FILE_REQUEST;//资源页请求成功
}

void HttpConnect::unmap()//解除资源页文件映射的内存
{
    if (fileAddress) {
        munmap( fileAddress, fileStat.st_size );//解除映射
        fileAddress = nullptr;
    }
}

bool HttpConnect::write()//将资源页文件发送给客户端
{
    int temp = 0;
    int bytes_have_send = 0;
    int bytes_to_send = writeIdx;
    if (bytes_to_send == 0) {
        modFd( epollFd, connectFd, EPOLLIN );//EPOLLONESHOT事件每次需要重置事件
        init();
        return true;
    }

    while (true)//
    {
        temp = writev( connectFd, ioVector,
                       ioVectorCount );//集中写，connectFd是http连接对应的描述符，ioVector是iovec结构体数组表示内存块地址，ioVectorCount是数组的长度即多少个内存块将一次集中写到connectFd
        if (temp <= -1)//集中写失败
        {
            if (errno == EAGAIN) {
                modFd( epollFd, connectFd, EPOLLOUT );//重置EPOLLONESHOT事件,注册可写事件表示若connectFd没有写失败则关闭连接
                return true;
            }
            unmap();//解除内存映射
            return false;
        }

        bytes_to_send -= temp;//待发送数据
        bytes_have_send += temp;//已发送数据
        if (bytes_to_send <= bytes_have_send) {
            unmap();//该资源页已经发送完毕该解除映射
            if (linger)//若要保持该http连接
            {
                init();//初始化http连接
                modFd( epollFd, connectFd, EPOLLIN );
                return true;
            } else {
                modFd( epollFd, connectFd, EPOLLIN );
                return false;
            }
        }
    }
}

bool HttpConnect::addResponse(const char* format, ...)//HTTP应答主要是将应答数据添加到写缓冲区writeBuf
{
    if (writeIdx >= WRITE_BUFFER_SIZE) {
        return false;
    }
    va_list arg_list;
    va_start( arg_list, format );
    int len = vsnprintf( writeBuf + writeIdx, WRITE_BUFFER_SIZE - 1 - writeIdx, format,
                         arg_list );//将fromat内容输出到writeBuf
    if (len >= (WRITE_BUFFER_SIZE - 1 - writeIdx)) {
        return false;
    }
    writeIdx += len;
    va_end( arg_list );
    return true;
}

bool HttpConnect::addStatusLine(int status, const char* title) {
    return addResponse( "%s %d %s\r\n", "HTTP/1.1", status, title );
}

bool HttpConnect::addHeaders(size_t content_len) {
    addContentLength( content_len );
    addLinger();
    addBlankLine();
}

bool HttpConnect::addContentLength(size_t content_len) {
    return addResponse( "Content-Length: %d\r\n", content_len );
}

bool HttpConnect::addLinger() {
    return addResponse( "Connection: %s\r\n", linger ? "keep-alive" : "close" );
}

bool HttpConnect::addBlankLine() {
    return addResponse( "%s", "\r\n" );
}

bool HttpConnect::addContent(const char* content) {
    return addResponse( "%s", content );
}

bool HttpConnect::processWrite(HttpCode ret) {
    switch (ret) {
        case HttpCode::INTERNAL_ERROR: {
            addStatusLine( 500, error_500_title );
            addHeaders( strlen( error_500_form ));
            if (!addContent( error_500_form )) {
                return false;
            }
            break;
        }
        case HttpCode::BAD_REQUEST: {
            addStatusLine( 400, error_400_title );
            addHeaders( strlen( error_400_form ));
            if (!addContent( error_400_form )) {
                return false;
            }
            break;
        }
        case HttpCode::NO_RESOURCE: {
            addStatusLine( 404, error_404_title );
            addHeaders( strlen( error_404_form ));
            if (!addContent( error_404_form )) {
                return false;
            }
            break;
        }
        case HttpCode::FORBIDDEN_REQUEST: {
            addStatusLine( 403, error_403_title );
            addHeaders( strlen( error_403_form ));
            if (!addContent( error_403_form )) {
                return false;
            }
            break;
        }
        case HttpCode::FILE_REQUEST: {
            addStatusLine( 200, ok_200_title );
            if (fileStat.st_size != 0) {
                addHeaders( fileStat.st_size );
                ioVector[0].iov_base = writeBuf;
                ioVector[0].iov_len = writeIdx;
                ioVector[1].iov_base = fileAddress;
                ioVector[1].iov_len = fileStat.st_size;
                ioVectorCount = 2;
                return true;
            } else {
                const char* ok_string = "<html><body></body></html>";
                addHeaders( strlen( ok_string ));
                if (!addContent( ok_string )) {
                    return false;
                }
            }
        }
        default: {
            return false;
        }
    }

    ioVector[0].iov_base = writeBuf;
    ioVector[0].iov_len = writeIdx;
    ioVectorCount = 1;
    return true;
}

void HttpConnect::process() {
    HttpCode read_ret = processRead();
    if (read_ret == HttpCode::NO_REQUEST) {
        modFd( epollFd, connectFd, EPOLLIN );
        return;
    }

    bool write_ret = processWrite( read_ret );
    if (!write_ret) {
        closeConnection();
    }

    modFd( epollFd, connectFd, EPOLLOUT );
}

char* HttpConnect::getLine() {
    return readBuf + startLine;
}

HttpConnect::HttpConnect() = default;

HttpConnect::~HttpConnect() = default;



















































////
//// Created by LiuYou on 2021/8/20.
////
//
//#include <sys/epoll.h>
//#include <fcntl.h>
//#include <cstring>
//#include <unistd.h>
//#include <cstdio>
//#include <cstdlib>
//#include <sys/mman.h>
//#include <sys/uio.h>
//#include <cstdarg>
//#include <cerrno>
//
//
//#include "HttpConnect2.hpp"
//
//
//static const char* DOC_ROOT = "/var/www/html";
//
//
//static const char* ERROR_500_TITLE = "Internal Error";
//
//static const char* ERROR_500_FORM = "There was an unusual problem serving the requested file.\n";
//
//
//static const char* ERROR_400_TITLE = "Bad Request";
//
//static const char* ERROR_400_FORM = "Your request has bad syntax or is inherently impossible to satisfy.\n";
//
//
//static const char* ERROR_404_TITLE = "Not Found";
//
//static const char* ERROR_404_FORM = "The requested file was not found on this server.\n";
//
//
//static const char* ERROR_403_TITLE = "Forbidden";
//
//static const char* ERROR_403_FORM = "Forbidden";
//
//
//static const char* OK_200_TITLE = "OK";
//
//
//int HttpConnect::epollFd = -1;
//int HttpConnect::userCount = 0;
//
//
//////////////////////////////////////////////////////////////////////////////////////
//
///*static*/ int setFdNonblocking(int fd) {
//    int oldOption = fcntl( fd, F_GETFL );
//    // 疑惑解开, 将文件描述符设置为非阻塞, 使用的是宏 O_NONBLOCK。
//    int newOption = oldOption | O_NONBLOCK;
//    fcntl( fd, F_SETFL, newOption );
//    return oldOption;
//}
//
///*static*/ void addFdToEpoll(int epollFd, int fd, bool oneShot) {
//    epoll_event epollEvent{};
//    epollEvent.data.fd = fd;
//    epollEvent.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
//    if (oneShot) {
//        epollEvent.events |= EPOLLONESHOT;
//    }
//    setFdNonblocking( fd );
//    epoll_ctl( epollFd, EPOLL_CTL_ADD, fd, &epollEvent );
//}
//
//
///*static*/ void removeFd(int epollFd, int fd) {
//    epoll_ctl( epollFd, EPOLL_CTL_DEL, fd, nullptr );
//    close( fd );
//}
//
///*static*/ void modFd(int epollFd, int fd, EPOLL_EVENTS events) {
//    epoll_event epollEvent{};
//    epollEvent.data.fd = fd;
//    epollEvent.events = events | EPOLLET | EPOLLONESHOT | EPOLLRDHUP;
//    epoll_ctl( epollFd, EPOLL_CTL_MOD, fd, &epollEvent );
//}
//
//
//
//
/////////////////////////////////////////////////////////////////////////////
//
//
//HttpConnect::HttpConnect() = default;
//
//HttpConnect::~HttpConnect() = default;
//
//void HttpConnect::init() {
//    checkState = CheckState::CHECK_STATE_REQUEST_LINE;
//    linger = false;
//
//    method = Method::GET;
//    url = nullptr;
//    version = nullptr;
//    contentLength = 0;
//    host = nullptr;
//    startLine = 0;
//    checkedIdx = 0;
//    readIdx = 0;
//    writeIdx = 0;
//
//    memset( readBuf, '\0', READ_BUFFER_SIZE );
//    memset( writeBuf, '\0', WRITE_BUFFER_SIZE );
//    memset( realFile, '\0', FILE_NAME_LEN );
//}
//
//void HttpConnect::init(int connectionFd, const sockaddr_in& address) {
//    connectFd = connectionFd;
//    remoteAddress = address;
//
//    /** 如下两行是为了避免 TIME_WAIT状态, 仅用于调试, 实际使用时应该去掉。*/
//    int reuse = 1;
//    setsockopt( this->connectFd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof( reuse ));
//    addFdToEpoll( epollFd, connectFd, true );
//    ++userCount;
//
//    init();
//}
//
//void HttpConnect::closeConnection(bool realClose) {
//    if (realClose && (connectFd != -1)) {
//        removeFd( epollFd, connectFd );
//        connectFd = -1;
//        /** 关闭一个连接时, 将客户总量减 1。*/
//        --userCount;
//    }
//}
//
///**
// * @brief 有线程池中的工作线程调用, 这是处理HTTP请求的入口函数。
// */
//void HttpConnect::process() {
//    HttpCode readRet = processRead();
//    if (readRet == HttpCode::NO_REQUEST) {
//        modFd( epollFd, connectFd, EPOLLIN );
//        return;
//    }
//    bool writeRet = processWrite( readRet );
//    if (!writeRet) {
//        closeConnection();
//    }
//    modFd( epollFd, connectFd, EPOLLOUT );
//}
//
///**
// * @brief 循环读取客户数据, 直到无数据可读或者对方关闭连接。
// * @return
// */
//bool HttpConnect::read() {
//    if (readIdx >= READ_BUFFER_SIZE) {
//        return false;
//    }
//
//    while (true) {
//        ssize_t rcvByteNum = recv( connectFd, readBuf + readIdx, READ_BUFFER_SIZE - readIdx, 0 );
//        if (rcvByteNum == -1) {
//            if (errno == EAGAIN || errno == EWOULDBLOCK) {
//                break;
//            }
//            return false;
//        } else if (rcvByteNum == 0) {
//            return false;
//        }
//        readIdx += rcvByteNum;
//    }
//    return true;
//}
//
///**
// * @brief 写HTTP相应。
// * @return
// */
//bool HttpConnect::write() {
//    ssize_t sedBytes = writeIdx;
//    if (sedBytes == 0) {
//        modFd( epollFd, connectFd, EPOLLIN );
//        init();
//        return true;
//    }
//
//    ssize_t bytesHaveSend = 0;
//    while (true) {
//        ssize_t readBytesNum = writev( connectFd, ioVector, ioVectorCount );
//        if (readBytesNum <= -1) {
//            /* 如果TCP写缓冲没有空间, 则等待下一轮EPOLLOUT事件。虽然在此期间, 服务器无法立刻接受到同一客户的下一个请求,
//             * 但这可以保证连接的完整性。*/
//            if (errno == EAGAIN) {
//                modFd( epollFd, connectFd, EPOLLOUT );
//                return true;
//            }
//            unmap();
//            return false;
//        }
//        sedBytes -= readBytesNum;
//        bytesHaveSend += readBytesNum;
//        if (sedBytes <= bytesHaveSend) {
//            /* 发送HTTP响应成功, 根据HTTP请求中的Connection字段决定是否李隆基关闭连接。*/
//            unmap();
//            if (linger) {
//                init();
//                modFd( epollFd, connectFd, EPOLLIN );
//                return true;
//            } else {
//                modFd( epollFd, connectFd, EPOLLIN );
//                return false;
//            }
//        }
//    }
//}
//
///**
// * @brief 主状态机。
// * @return
// */
//HttpCode HttpConnect::processRead() {
//    LineStatus lineStatus = LineStatus::LINE_OK;
//    char* text = nullptr;
//
//    while (((checkState == CheckState::CHECK_STATE_CONTENT) && (lineStatus == LineStatus::LINE_OK)) ||
//           ((lineStatus = parseLine()) == LineStatus::LINE_OK)) {
//        text = getLine();
//        startLine = checkedIdx;
////        printf( "got 1 http line: %s\n", text );
//        printf( "得到 1 http 行: %s\n", text );
//
//        switch (checkState) {
//            case CheckState::CHECK_STATE_REQUEST_LINE: {
//                HttpCode httpCode = parseRequestLine( text );
//                if (httpCode == HttpCode::BAD_REQUEST) {
//                    return HttpCode::BAD_REQUEST;
//                }
//                break;
//            }
//            case CheckState::CHECK_STATE_HEADER: {
//                HttpCode httpCode = parseHeaders( text );
//                if (httpCode == HttpCode::BAD_REQUEST) {
//                    return HttpCode::BAD_REQUEST;
//                } else if (httpCode == HttpCode::GET_REQUEST) {
//                    return doRequest();
//                }
//                break;
//            }
//            case CheckState::CHECK_STATE_CONTENT: {
//                HttpCode httpCode = parseContent( text );
//                if (httpCode == HttpCode::GET_REQUEST) {
//                    return doRequest();
//                }
//                lineStatus = LineStatus::LINE_OPEN;
//                break;
//            }
//            default: {
//                return HttpCode::INTERNAL_ERROR;
//            }
//        }
//    }
//
//    return HttpCode::NO_REQUEST;
//}
//
///**
// * @brief 从状态机。
// * @return
// */
//LineStatus HttpConnect::parseLine() {
//    char temp;
//    for (; checkedIdx < readIdx; ++checkedIdx) {
//        temp = readBuf[checkedIdx];
//        if (temp == '\r') {
//            if ((checkedIdx + 1) == readIdx) {
//                return LineStatus::LINE_OPEN;
//            } else if (readBuf[checkedIdx + 1] == '\n') {
//                readBuf[checkedIdx] = '\0';
//                readBuf[checkedIdx] = '\0';
//                return LineStatus::LINE_OK;
//            }
//            return LineStatus::LINE_BAD;
//        } else if (temp == '\n') {
//            if ((checkedIdx > 1) && (readBuf[checkedIdx - 1] == '\r')) {
//                readBuf[checkedIdx - 1] = '\0';
//                readBuf[checkedIdx++] = '\0';
//                return LineStatus::LINE_OK;
//            }
//            return LineStatus::LINE_BAD;
//        }
//    }
//    return LineStatus::LINE_OPEN;
//}
//
//char* HttpConnect::getLine() {
//    return readBuf + startLine;
//}
//
//HttpCode HttpConnect::parseRequestLine(char* text) {
//    url = strpbrk( text, " \t" );
//    if (!url) {
//        return HttpCode::BAD_REQUEST;
//    }
//    *url++ = '\0';
//
//    char* method = text;
//    if (strcasecmp( method, "GET" ) == 0) {
//        this->method = Method::GET;
//    } else {
//        return HttpCode::BAD_REQUEST;
//    }
//
//    url += strspn( url, " \t" );
//    version = strpbrk( url, " \t" );
//    if (!version) {
//        return HttpCode::BAD_REQUEST;
//    }
//    *version++ = '\0';
//    version += strspn( version, " \t" );
//    if (strcasecmp( version, "HTTP/1.1" ) != 0) {
//        return HttpCode::BAD_REQUEST;
//    }
//    if (strncasecmp( url, "http://", 7 ) == 0) {
//        url += 7;
//        url = strchr( url, '/' );
//    }
//    if (!url || url[0] != '/') {
//        return HttpCode::BAD_REQUEST;
//    }
//    checkState = CheckState::CHECK_STATE_HEADER;
//    return HttpCode::NO_REQUEST;
//}
//
///**
// * @brief 解析http请求的一个头部信息。
// * @param text
// * @return
// */
//HttpCode HttpConnect::parseHeaders(char* text) {
//    if (text[0] == '\0') {
//        /* 如果HTTP请求有消息体, 则还需要读取contentLength字节的消息体, 状态机转移到 CHECK_STATE_CONTENT状态。*/
//        if (contentLength != 0) {
//            checkState = CheckState::CHECK_STATE_CONTENT;
//            return HttpCode::NO_REQUEST;
//        }
//        /* 否则说明我们已经得到了一个完整的HTTP请求。*/
//        return HttpCode::GET_REQUEST;
//    }
//        /* 处理Connection头部字段。*/
//    else if (strncasecmp( text, "Connection:", 11 ) == 0) {
//        text += 11;
//        text += strspn( text, " \t" );
//        if (strcasecmp( text, "keep-alive" ) == 0) {
//            linger = true;
//        }
//    }
//        /* 处理Content-Length头部字段。*/
//    else if (strncasecmp( text, "Content-Length:", 15 ) == 0) {
//        text += 15;
//        text += strspn( text, " \t" );
//        contentLength = atol( text );
//    }
//        /* 处理Host头部字段。*/
//    else if (strncasecmp( text, "Host:", 5 ) == 0) {
//        text += 5;
//        text += strspn( text, " \t" );
//        host = text;
//    } else {
//        printf( "Oops! unknown header %s\n", text );
//    }
//    return HttpCode::NO_REQUEST;
//}
//
///**
// * @brief 当得到一个完整、正确的HTTP请求时, 我们就分析目标文件的属性。如果目标文件存在、对所有用户可读, 且不是目录,
// * 则使用 mmap() 将其映射到内存地址 fileAddress处, 并告诉调用者获取文件成功。
// * @return
// */
//HttpCode HttpConnect::doRequest() {
//    strcpy( realFile, DOC_ROOT );
//    size_t len = strlen( DOC_ROOT );
//    strncpy( realFile + len, url, FILE_NAME_LEN - len - 1 );
//    if (stat( realFile, &fileStat ) < 0) {
//        return HttpCode::NO_RESOURCE;
//    }
//    if (!(fileStat.st_mode & S_IROTH)) {
//        return HttpCode::FORBIDDEN_REQUEST;
//    }
//    if (S_ISDIR( fileStat.st_mode )) {
//        return HttpCode::BAD_REQUEST;
//    }
//    int fd = open( realFile, O_RDONLY );
//    fileAddress = (char*) mmap( nullptr, fileStat.st_size, PROT_READ, MAP_PRIVATE, fd, 0 );
//    close( fd );
//    return HttpCode::FILE_REQUEST;
//}
//
///**
// * @brief 我们没有真正解析http请求的消息体, 只是判断它是否被完整地读入了。
// * @param text
// * @return
// */
//HttpCode HttpConnect::parseContent(char* text) {
//    if (readIdx >= (contentLength + checkedIdx)) {
//        text[contentLength] = '\0';
//        return HttpCode::GET_REQUEST;
//    }
//    return HttpCode::NO_REQUEST;
//}
//
//
///**
// * @brief 根据服务器处理HTTP请求的结果, 决定返回给客户端的内容。
// * @param code
// * @return
// */
//bool HttpConnect::processWrite(HttpCode code) {
//    switch (code) {
//        case HttpCode::INTERNAL_ERROR: {
//            addStatusLine( 500, ERROR_500_TITLE );
//            addHeaders( strlen( ERROR_500_FORM ));
//            if (!addContent( ERROR_500_FORM )) {
//                return false;
//            }
//            break;
//        }
//        case HttpCode::BAD_REQUEST: {
//            addStatusLine( 400, ERROR_400_TITLE );
//            addHeaders( strlen( ERROR_400_FORM ));
//            if (!addContent( ERROR_400_FORM )) {
//                return false;
//            }
//            break;
//        }
//        case HttpCode::NO_RESOURCE: {
//            addStatusLine( 404, ERROR_404_TITLE );
//            addHeaders( strlen( ERROR_404_FORM ));
//            if (!addContent( ERROR_404_FORM )) {
//                return false;
//            }
//            break;
//        }
//        case HttpCode::FORBIDDEN_REQUEST: {
//            addStatusLine( 403, ERROR_403_TITLE );
//            addHeaders( strlen( ERROR_403_FORM ));
//            if (!addContent( ERROR_403_FORM )) {
//                return false;
//            }
//            break;
//        }
//        case HttpCode::FILE_REQUEST: {
//            addStatusLine( 200, OK_200_TITLE );
//            if (fileStat.st_size != 0) {
//                addHeaders( fileStat.st_size );
//                ioVector[0].iov_base = writeBuf;
//                ioVector[0].iov_len = writeIdx;
//                ioVector[1].iov_base = fileAddress;
//                ioVector[1].iov_len = fileStat.st_size;
//                ioVectorCount = 2;
//                return true;
//            } else {
//                const char* okStr = "<html><body></body></html>";
//                addHeaders( strlen( okStr ));
//                if (!addContent( okStr )) {
//                    return false;
//                }
//            }
//        }
//        default: {
//            return false;
//        }
//    }
//
//    ioVector[0].iov_base = writeBuf;
//    ioVector[0].iov_len = writeIdx;
//    ioVectorCount = 1;
//    return true;
//}
//
//bool HttpConnect::addStatusLine(int status, const char* title) {
//    return addResponse( "%s %d %s\r\n", "HTTP/1.1", status, title );
//}
//
///**
// * @brief 往写缓冲中写入待发送的数据。
// * @param format
// * @param ...
// * @return
// */
//bool HttpConnect::addResponse(const char* format, ...) {
//    if (writeIdx >= WRITE_BUFFER_SIZE) {
//        return false;
//    }
//    va_list argList;
//    va_start( argList, format );
//    int len = vsnprintf( writeBuf + writeIdx, WRITE_BUFFER_SIZE - 1 - writeIdx, format, argList );
//    if (len >= (WRITE_BUFFER_SIZE - 1 - writeIdx)) {
//        return false;
//    }
//    writeIdx += len;
//    va_end( argList );
//    return true;
//}
//
//bool HttpConnect::addHeaders(size_t contentLength) {
//    addContentLength( contentLength );
//    addLinger();
//    addBlankLine();
////    return false;
//}
//
//bool HttpConnect::addContentLength(size_t contentLength) {
//    return addResponse( "Content-Length: %d\r\n", contentLength );
//}
//
//bool HttpConnect::addLinger() {
//    return addResponse( "Connection: %s\r\n", linger ? "keep-alive" : "close" );
//}
//
//bool HttpConnect::addBlankLine() {
//    return addResponse( "%s", "\r\n" );
//}
//
//bool HttpConnect::addContent(const char* content) {
//    return addResponse( "%s", content );
//}
//
///**
// * @brief 对内存映射区执行 munmap() 操作。
// */
//void HttpConnect::unmap() {
//    if (fileAddress) {
//        munmap( fileAddress, fileStat.st_size );
//        fileAddress = nullptr;
//    }
//}
//
//
//
//
